#!/usr/bin/env python
# WPP Test module.
from __future__ import division
import sys
import os
import csv
from time import strftime
from nose.tools import assert_equal, with_setup
from numpy import argsort, vstack
from logging import getLogger, Formatter, DEBUG, StreamHandler
log = getLogger('wpp.indoor')
import gc

from wpp.location import fixPosWLAN_indoor
from wpp.db import WppDB
from wpp.config import dbsvrs, DB_ONLINE, csv_fmt_indoorfp, CLUSTERKEYSIZE, TESTFILE, DEBUG_ALGO, iac_graph


def usage():
    print """
test.py - Copyleft 2009-%s Yan Xiaotian, xiaotian.yan@gmail.com.
WPP test module.

usage:
    test <option> <infile>
option:
    -h --help             :  Show this help.
    -i --indoor           :  indoor pos test.
    -v --verbose          :  Verbose mode.
e.g.
    test.py -f <csvfile> -i
""" % strftime('%Y')


#def eval_accuracy(iac_pos, iac_real):
    # TODO: accuracy_level = eval_accuracy(iac_pos, iac_real)
    # accuracy_level: { 'name': 'degrade', 'err': 10 } 


def test_wlanpos_indoor():
    """ 
    Accuracy test for indoor WLAN positioning.
    """
    log.info('\n') # newline in "nosetests -v -s" mode.
    # csv read.
    fps = csv.DictReader(file(TESTFILE), csv_fmt_indoorfp)
    # db init.
    dbsvr = dbsvrs[DB_ONLINE] 
    wppdb = WppDB(dsn=dbsvr['dsn'], dbtype=dbsvr['dbtype'])
    ig_f19 = iac_graph[2][19]
    # degrade case: len(iac_real.split('.')) - len(iac_pos.split('.')) = 1
    pos_stats = { 'fail': 0, 'hit': 0, 'miss': 0, 'degrade': 0, 'cdf': {5: 0, 10: 0}, 'miss_ids':[] }
    for i, fp in enumerate(fps):
        macs = fp['macs'].split('|') 
        rsss = fp['rsss'].split('|') 
        INTERSET = min(CLUSTERKEYSIZE, len(macs)) 
        idxs_max = argsort(rsss)[:INTERSET]
        macsrsss = vstack((macs, rsss))[:,idxs_max]
        gc.disable()
        wlanloc = fixPosWLAN_indoor(INTERSET, macsrsss, wppdb, DEBUG_ALGO)
        gc.enable()
        if not wlanloc:
            log.error('Positioning Failed!')
            continue
        iac_pos, h_pos = wlanloc[:2]
        iac_real = fp['iac']; h_real = fp['h']
        try:
            assert_equal([ iac_real, h_real ], [ iac_pos, h_pos ])
        except AssertionError:
            # TODO: accuracy_level = eval_accuracy(iac_pos, iac_real)
            # accuracy_level: { 'name': 'degrade', 'err': 10 } 
            #if iac_real.startswith(iac_pos) and len(iac_real.split('.')) - len(iac_pos.split('.')) == 1:
            iacs_pos = iac_pos.split('|')
            #log.info(iacs_pos)
            iacs_degrade = []
            for x in iacs_pos:
                iacs_degrade.extend( ig_f19[x]['n'] )
            iacs_degrade = iacs_degrade + iacs_pos
            #log.info(iacs_degrade)
            if iac_real in iacs_degrade:
                pos_stats['degrade'] += 1
                log.warn('[%03d]: [DEGRADE] %s --> %s' % \
                        (i+1, '_'.join([iac_real, h_real]), '_'.join([iac_pos, h_pos])) )
            else:
                pos_stats['miss'] += 1
                log.error('[%03d]: [MISS] %s --> %s' % \
                        (i+1, '_'.join([iac_real, h_real]), '_'.join([iac_pos, h_pos])) )
                pos_stats['miss_ids'].append(i+1)
            continue
        log.info('[%03d]: [HIT ] %s' % (i+1, '_'.join([iac_real, h_real])) )
        pos_stats['hit'] += 1
    pos_stats['cdf'][5]  = '%.2f' % ( pos_stats['hit'] / (i+1) )
    pos_stats['cdf'][10] = '%.2f' % ( (pos_stats['hit']+pos_stats['degrade']) / (i+1) )
    log.info(pos_stats)


def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hiv",
            ["help", "indoor", "verbose"])
    except getopt.GetoptError:
        usage()
        sys.exit(99)

    if not opts: usage(); sys.exit(0)

    for o,a in opts:
        if o in ("-i", "--indoor"):
            test_indoor_pos = True
        elif o in ("-v", "--verbose"):
            verbose = True
            from pprint import pformat as PF
        elif o in ("-h", "--help"):
            usage(); sys.exit(0)
        else:
            print 'Parameter NOT supported: %s' % o
            usage(); sys.exit(99)

    if test_indoor_pos:
        test_wlanpos_indoor()


if __name__ == "__main__":
    import getopt
    try:
        import psyco
        #psyco.bind(scanWLAN_OS)
        psyco.bind(test_wlanpos_indoor)
        #psyco.full()
        #psyco.log()
        #psyco.profile(0.3)
    except ImportError:
        pass

    main()
